/**
 * @file power_manage.c
 * @Synopsis  系统电源管理
 * @author SWFighter
 * @version 1.0.0V
 * @date 2018-07-13
 */
#include "power_manage.h"

#ifdef USEING_DEBUG_POWER
#define rt_kprintf       rt_kprintf
#else
#define rt_kprintf(...)       
#endif

#define USEING_SYS_STOP_MODE
#define USEING_SYS_SLEPP_MODE

#ifndef RTC_ALARM_WAKEUP_TIME
#define RTC_ALARM_WAKEUP_TIME (60*5)
#endif
/***************************************************************************************************/
#define POWER_MANAGE_DEBUG  31   //电源管理调试开关

/***************************************************************************************************/
/* test thread low power useing */

typedef struct 
{
  volatile rt_uint32_t WorkFlag;			// 工作标志每一个位代表一个线程
  volatile rt_uint8_t  IsSleep;			// 是否需要进行休眠判断
}SystemSleepDef,*SystemSleepDef_p;

static SystemSleepDef SysSleep = 
{
  0,
  1, //没有一个线程开始工作时不判断休眠
};


/** 
  @brief  关闭stm32所有GPIO
  @param  none 
  @retval none
  */
static void stm32_gpio_all_close(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  //GPIO_Init(GPIOA,&GPIO_InitStructure);
  //GPIO_Init(GPIOB,&GPIO_InitStructure);
  //GPIO_Init(GPIOC,&GPIO_InitStructure);
  //GPIO_Init(GPIOD,&GPIO_InitStructure);
  //GPIO_Init(GPIOE,&GPIO_InitStructure);
  //GPIO_Init(GPIOF,&GPIO_InitStructure);

}

/** 
  @brief  进入低功耗时时钟控制
  @param  none 
  @retval none
  */
static void stm32_sleep_rcc_manage(FunctionalState NewState)
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|
      RCC_APB2Periph_GPIOA|
      RCC_APB2Periph_GPIOB|
      //RCC_APB2Periph_GPIOC|
      //RCC_APB2Periph_GPIOD|
      //RCC_APB2Periph_GPIOE|
      //RCC_APB2Periph_GPIOF|
      RCC_APB2Periph_USART1|
      RCC_APB2Periph_SPI1, NewState);

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|
      RCC_APB1Periph_SPI2|
      RCC_APB1Periph_USART2|
      RCC_APB1Periph_USART3|
      RCC_APB1Periph_UART4|
      RCC_APB1Periph_PWR|
      RCC_APB1Periph_TIM3|
      RCC_APB1Periph_TIM4|
      RCC_APB1Periph_TIM5,NewState);		
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, (NewState == ENABLE)?DISABLE:ENABLE);
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, (NewState == ENABLE)?DISABLE:ENABLE);
  SPI_Cmd(SPI1,NewState);
  SPI_Cmd(SPI2,NewState);

  USART_Cmd(USART1,NewState);
  USART_Cmd(USART2,NewState);
  USART_Cmd(USART3,NewState);
  USART_Cmd(UART4,NewState);
}


/** 
  @brief  备份和还原STM32寄存器
  @param  cmd  
  @arg RT_TRUE 备份
  @retval none
  */
static void stm32_backup_restore(rt_bool_t cmd)
{
  static GPIO_TypeDef *gpio;
  //static EXTI_TypeDef *exti;
  //static AFIO_TypeDef *afio;

  if(cmd == RT_TRUE)
  {
    gpio = rt_calloc(6,sizeof(GPIO_TypeDef));
    RT_ASSERT(gpio != RT_NULL);

    /*exti = rt_calloc(1,sizeof(EXTI_TypeDef));
      RT_ASSERT(exti != RT_NULL);

      afio = rt_calloc(1,sizeof(AFIO_TypeDef));
      RT_ASSERT(afio != RT_NULL);*/

    // 备份GPIO寄存器
    gpio[0] = *GPIOA;
    gpio[1] = *GPIOB;
    gpio[2] = *GPIOC;
    //gpio[3] = *GPIOD;
    //gpio[4] = *GPIOE;
    //gpio[5] = *GPIOF;

    // 备份中断寄存器
    //*exti = *EXTI;

    // 备份AFIO
    //*afio =	*AFIO;
  }
  else
  {
    // 还原GPIO寄存器
    *GPIOA = gpio[0];
    *GPIOB = gpio[1];
    *GPIOC = gpio[2];
    //*GPIOD = gpio[3];
    //*GPIOE = gpio[4];
    //*GPIOF = gpio[5];

    // 还原中断寄存器
    //*EXTI = *exti;

    // 还原AFIO
    //*AFIO = *afio;


    rt_free(gpio);
    gpio = RT_NULL;

    /*rt_free(exti);
      exti = RT_NULL;

      rt_free(afio);
      afio = RT_NULL;*/

  }
}


/**
 * @brief  This function handles RTC Alarm interrupt request.
 * @param  None
 * @retval None
 */
int RTC_Alarm_Config(void)
{
  EXTI_InitTypeDef EXTI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  u32 count=0x200;

  /* Configure EXTI Line17(RTC Alarm) to generate an interrupt on rising edge */
  EXTI_ClearITPendingBit(EXTI_Line17);
  EXTI_InitStructure.EXTI_Line = EXTI_Line17;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable PWR and BKP clocks */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	PWR_BackupAccessCmd(ENABLE);

	if (BKP_ReadBackupRegister(BKP_DR2) == 0xA5A5)
	{
		rt_kprintf("RTC It's Configured\n");
		//return 0;
	}
	rt_kprintf("RTC It's Configured %x\n",BKP_ReadBackupRegister(BKP_DR2));

	RCC_LSICmd(ENABLE);
  /* Wait till LSE is ready */
  while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET && count)
  {
    count--;
  }

  /* Select the RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);//使用内部时钟源

  /* Enable the RTC Clock */
  RCC_RTCCLKCmd(ENABLE);

  /* RTC configuration -------------------------------------------------------*/
  /* Wait for RTC APB registers synchronisation */
  RTC_WaitForSynchro();

  /* Set the RTC time base to 1s */
  RTC_SetPrescaler(40000);//内部时钟
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Enable the RTC Alarm interrupt */
  RTC_ITConfig(RTC_IT_ALR, ENABLE);
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  //RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, DISABLE);
  BKP_WriteBackupRegister(BKP_DR2, 0xA5A5);
	rt_kprintf("RTC Alarm Init ... ok\n");
  return 0;
}
INIT_DEVICE_EXPORT(RTC_Alarm_Config);


extern void update_sem_release(void);
/**
 * @brief  This function handles RTC Alarm interrupt request.
 * @param  None
 * @retval None
 */
void RTCAlarm_IRQHandler(void)
{
  rt_interrupt_enter();
  if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
  {
    /* Clear EXTI line17 pending bit */
    EXTI_ClearITPendingBit(EXTI_Line17);

    /* Check if the Wake-Up flag is set */
    if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)
    {
      /* Clear Wake Up flag */
      PWR_ClearFlag(PWR_FLAG_WU);
    }

    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();   
    /* Clear RTC Alarm interrupt pending bit */
    RTC_ClearITPendingBit(RTC_IT_ALR);
    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();
    //battery_energy_check_20p();//检测电池
    //BKP_WriteBackupRegister(BKP_DR2,PRO_EVT_ASK);
    update_event_mail(PRO_EVT_ASK);
    rt_interrupt_leave();
  }
}


/** 
  @brief  设置RTC报警事件的时间
  @param  none 
  @retval none
  */
void RTC_Alarm_Wakeup_Time(rt_uint32_t sec)
{
  /* Wait till RTC Second event occurs */
  RTC_ClearFlag(RTC_FLAG_SEC);
  while(RTC_GetFlagStatus(RTC_FLAG_SEC) == RESET);

  /* Alarm in 3 second */
  RTC_SetAlarm(RTC_GetCounter()+ sec);
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  将调试口设置为RX中断输入唤醒系统
 *
 * @Param mode RT_TRUE 使能
 */
/* ----------------------------------------------------------------------------*/
void stm32_debug_uart_config(rt_bool_t mode)
{
#ifdef USEING_DEBUG_WAKEUP
  GPIO_InitTypeDef GPIO_InitStructure;
  EXTI_InitTypeDef EXTI_InitStructure;


  if(mode == RT_TRUE)
  {
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource11);
    EXTI_InitStructure.EXTI_Line=EXTI_Line11;	//KEY2
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = DISABLE;
    EXTI_Init(&EXTI_InitStructure);	 	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
    EXTI_ClearITPendingBit(EXTI_Line11);

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_11;//PC11
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置成上拉输入
    GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
    // 配置Uart4
    USART_Cmd(UART4,ENABLE);
  }
  else
  { 	
    // 配置RX中断输入
    USART_Cmd(UART4,DISABLE);

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_11;//PC11
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
    GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource11);

    EXTI_InitStructure.EXTI_Line=EXTI_Line11;	//KEY2
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);	 	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
    EXTI_ClearITPendingBit(EXTI_Line11);
  }
#endif
}


static rt_uint32_t update_ask_time = RTC_ALARM_WAKEUP_TIME;

/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  更新询问周期 
 *
 * @Returns   返回周期字段 
 */
/* ----------------------------------------------------------------------------*/
rt_uint32_t* update_ask_cycle_get(void)
{
	return &update_ask_time;
}

void set_system_stop_cycle(rt_uint32_t value)
{
	update_ask_time = value;
}

/** 
  @brief  休眠之前引脚处理
  @param  none 
  @retval none
  */
static void stm32_sleep_gpio_config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_StructInit(&GPIO_InitStructure);

	rt_kprintf("systemp stop time %d\n",update_ask_time);
	
	//关闭LCD
  rt_pin_write(LCD_POWR_PIN, 0);

  // 关闭GSM
  rt_pin_write(GSM_POWR_PIN, 0);
	
  // 设置空闲管脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|
    GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|
    GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|
    GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
  GPIO_Init(GPIOB,&GPIO_InitStructure);

  //关闭A端口
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|
    GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|
    GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|
    GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA,&GPIO_InitStructure);

	//关闭C端口
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOC,&GPIO_InitStructure);

	//关闭串口
	USART_Cmd(USART1,DISABLE);
	USART_Cmd(USART2,DISABLE);

	ADC_Cmd(ADC1,DISABLE); 
	
  //清除外部中断请求
  EXTI_ClearFlag(0xff);
  EXTI_ClearITPendingBit(0xff);
	//rt_kprintf("systemp stop time %d\n",update_ask_time);
  // 设置RTC 唤醒时间
  RTC_Alarm_Wakeup_Time(update_ask_time);

  //stm32_debug_uart_config(RT_FALSE);
  //stm32_gpio_all_close();
}


/**
 * @brief  Configures system clock after wake-up from STOP: enable HSE, PLL
 *   and select PLL as system clock source.
 * @param  None
 * @retval None
 */
void SYSCLKConfig_STOP(void)
{
  ErrorStatus HSEStartUpStatus; 

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {

#ifdef STM32F10X_CL
    /* Enable PLL2 */ 
    RCC_PLL2Cmd(ENABLE);

    /* Wait till PLL2 is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)
    {
    }
#endif

    /* Enable PLL */ 
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }
}


/** 
  @brief  stm32进入睡眠模式
  @param  none 
  @retval none
  */
static void stm32_sleep_mode_entry(void)
{ 
  //rt_dprintf(POWER_MANAGE_DEBUG,("STM32 Entry Sleep\n"));
  __WFI();
  //rt_dprintf(POWER_MANAGE_DEBUG,("STM32  Exit Sleep\n"));
}

/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  读取RTC备份寄存器1
 *
 * @Returns   
 */
/* ----------------------------------------------------------------------------*/
rt_uint16_t read_rtc_bkp1(void)
{
	rt_uint16_t value;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);// PWR的使能。
	value = BKP_ReadBackupRegister(BKP_DR1);
	
	rt_kprintf("bkp1=%d\n",value);
	return value;
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  设置备份寄存器涉睡眠事件 
 */
/* ----------------------------------------------------------------------------*/
void set_bkp_sleep_evt(void)
{
	rt_uint16_t value;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);// PWR的使能。
	value = BKP_ReadBackupRegister(BKP_DR1);
	rt_kprintf(">>>>>>>>>>>>>bkp1%d\n",value);
	value |= SYS_EVT_WAKEUP;
	rt_kprintf("bkp1%d\n",value);
	BKP_WriteBackupRegister(BKP_DR1,value);
}

/** 
  @brief  stm32进入停机模式
  @param  none 
  @retval none
  */
static void stm32_stop_mode_entry(void)
{	
  // 调度上锁
  rt_enter_critical();

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);// PWR的使能。
	set_bkp_sleep_evt();
	save_sysflow_bkp();
	stm32_backup_restore(RT_TRUE);// 备份gpio
  PWR_WakeUpPinCmd(ENABLE);//使能唤醒管脚功能
  stm32_sleep_gpio_config();//配置STM32进入最低功耗

  //PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); // 进入睡眠。 
  PWR_EnterSTANDBYMode();//进入待机模式

	//恢复两个串口
	USART_Cmd(USART1,ENABLE);
	USART_Cmd(USART2,ENABLE);
  

  stm32_backup_restore(RT_FALSE);// 还原gpio
  SYSCLKConfig_STOP();// 配置系统停止后时钟

  
  PWR_ClearFlag(PWR_FLAG_WU);// 清除唤醒标志
  PWR_ClearFlag(PWR_FLAG_SB);// 清除待机模式

  // 调度解锁
  rt_exit_critical();
}


/** 
  @brief  空闲线程处理
  @param  none 
  @retval none
  */
void rt_thread_idle_process(void)
{
  static rt_uint32_t cnt = 0;

  if((SysSleep.IsSleep == 0)&&(SysSleep.WorkFlag == 0))//没有线程工作但是也没有睡眠
  {
  	rt_kprintf("cnt=%d,%d %d\n",cnt,SysSleep.IsSleep,SysSleep.WorkFlag);
    // 检测有没有任务就绪 
    if(cnt++ < 5)
    {
      return ;
    }
    else
    {
      cnt = 0;
    }
    // 进入停机模式
    SysSleep.IsSleep = 1;
#ifdef USEING_SYS_STOP_MODE
    stm32_stop_mode_entry();
#endif
  }
  else
  {
    // CPU休眠
#ifdef USEING_SYS_SLEPP_MODE
    stm32_sleep_mode_entry();
#endif
		cnt = 0;
  }
}



/** 
  @brief  设置空闲线程钩子函数
  @param  none 
  @retval none
  */
int rt_thread_idle_set(void)
{
  rt_thread_idle_sethook(rt_thread_idle_process);

  return 0;
}
#ifdef USING_PowerManage
INIT_APP_EXPORT(rt_thread_idle_set);
#endif


/** 
  @brief 需要进行休眠与工作的线程名字
  */
static const char ThreadName[][RT_NAME_MAX] =
{
  "proto",
	"show"
};
/** 
  @brief  thread status manage
  @param  thread object
  @param  status 0:work or 1:sleep
  @retval none 
  */
void rt_thread_status_manage(rt_thread_t thread,rt_uint8_t status)
{
  /* flag 的每一个位代表一个线程 */
  rt_uint32_t flag;
  rt_uint8_t  i;

  // 读取之前的线程工作状态
  flag = SysSleep.WorkFlag;

  // 将进入工作的线程位置1 进入休眠的线程位置0
  for(i=0;i<sizeof(ThreadName)/RT_NAME_MAX;i++)
  {
  	rt_kprintf("thread %s\n",thread->name);
    if(rt_strcmp(thread->name,ThreadName[i]) == 0)
    {
      status ? (flag &= ~(0x01<<i)):(flag |= (0x01<<i));
    }
  }
  // 如果线程工作状态位有变化显示
  if(flag != SysSleep.WorkFlag)
  {
    SysSleep.WorkFlag = flag;
    SysSleep.IsSleep = 0;

    // 调试信息
    if(SysSleep.WorkFlag != 0)
    {
      rt_kprintf("Status:%x Thread In Work\n",SysSleep.WorkFlag);
      for(i=0;i<sizeof(ThreadName)/RT_NAME_MAX;i++)
      {
        if(flag & 0x01<<i)
        {
          rt_kprintf("\"%s\" ",ThreadName[i]);
        }
      }
      rt_kprintf("\n");
    }
    else
    {
      rt_kprintf("STM32 System Entry Stop Mode %d %d\n",SysSleep.IsSleep,SysSleep.WorkFlag);
    }
  }
}


/** 
  @brief  thread entry work 
  @param  thread object
  @retval none 
  */
void rt_thread_entry_work(rt_thread_t thread)
{	
  rt_thread_status_manage(thread,0);
}


/** 
  @brief  thread entry sleep 
  @param  thread object
  @retval none 
  */
void rt_thread_entry_sleep(rt_thread_t thread)
{
  rt_thread_status_manage(thread,1);
}




#ifdef RT_USING_FINSH
#include <finsh.h>

void sleepManage(rt_uint8_t cmd)
{
  switch(cmd)
  {
    case 0:
      {
        rt_kprintf("idle_set:\n");
        rt_kprintf("cmd:0 --help");
        rt_kprintf("cmd:1 --set sleep work mode\n");
        rt_kprintf("cmd:2 --cancel sleep work mode");
        break;
      }
    case 1:
      {
        rt_thread_idle_sethook(rt_thread_idle_process);
        break;
      }
    case 2:
      {
        rt_thread_idle_sethook(RT_NULL);
      }
  }
}

FINSH_FUNCTION_EXPORT(sleepManage,"(cmd) sleep mode manage cmd");

#endif

